package controllers.GestionTratamientoDatos.Metodos.Correccion.Metodos;

import controllers.GestionTratamientoDatos.Metodos.Correccion.MetodoCorreccionBase;
import models.Hidpuntomonitoreo;
import models.Hidregistro;
import models.Hidtipopuntomonitoreo;
import models.Hidtiporegistro;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 * Created with IntelliJ IDEA.
 * User: Daniel
 * Date: 22/04/13
 * Time: 09:39 AM
 * To change this template use File | Settings | File Templates.
 */
public class CorrelacionSimple extends MetodoCorreccionBase {

    public RegresionLineal regresionLineal;

    public CorrelacionSimple(List<Hidregistro> serieEntrada, int intervaloDias) {
        super(serieEntrada, intervaloDias);
        //regresionLineal = new RegresionLineal(serieEntrada);
    }

    @Override
    public void Corregir()
    {
        //System.out.println("1");
        List<Hidregistro> serieOriginal = ObtenerSerieOriginalCompleta();
        //System.out.println("2 + tamSerieOrig: " + serieOriginal.size());
        regresionLineal = new RegresionLineal(serieOriginal);
        //System.out.println("3");

        List<Hidregistro> mejorSerieParaCorrelacion = ObtenerMejorSerieParaCorrelacionar();
        //System.out.println("4 tamMejorSerie: " + mejorSerieParaCorrelacion.size());
        //System.out.println("4");
        Correlacionar(serieOriginal, mejorSerieParaCorrelacion);
        //System.out.println("5");
        DeterminarDatosCorregidos();
        //System.out.println("6");
    }

    public void Correlacionar(List<Hidregistro> serieOriginal, List<Hidregistro> serieEstacionNueva)
    {
        //System.out.println("4.1");
        //if(CoeficientePearson(serieOriginal,serieEstacionNueva) > 0.7)
        //{
            regresionLineal.RealizarRegresion(serieEstacionNueva);
        //}
        //System.out.println("cte: " + regresionLineal.getConstante() + " pendiente: " + regresionLineal.getPendiente());
        //System.out.println("4.2");
    }

    public double CoeficientePearson(List<Hidregistro> serieX, List<Hidregistro> serieY)
    {
        double SXY = 0;
        double SX = 0;
        double SY = 0;
        double SX2 = 0;
        double SY2 = 0;

        //numero de elementos: N
        int N = serieX.size();

        for (int i = 0; i < N; i++)
        {
            SXY += serieX.get(i).getRegval() * serieY.get(i).getRegval();
            SX += serieX.get(i).getRegval();
            SY += serieY.get(i).getRegval();
            SX2 += serieX.get(i).getRegval() * serieX.get(i).getRegval();
            SY2 += serieY.get(i).getRegval() * serieY.get(i).getRegval();
        }

        // pf = (N*SXY - SX*SY)/(sqrt((N*SX2 - SX.^2)*(N*SY2 - SY.^2)));
        double coeficientePearson = (N * SXY - SX * SY) / (Math.sqrt((N * SX2 - Math.pow(SX,2))*(N * SY2 - Math.pow(SY,2))));

        return coeficientePearson;
    }

    public void DeterminarDatosCorregidos()
    {
        List<Hidregistro> hidregistros = new ArrayList<Hidregistro>();

        for (int i = 0; i < getSerieEntrada().size() - 1; i++)
        {
            Date fechaInicio = getSerieEntrada().get(i).getRegfech();
            Date fechaFin = getSerieEntrada().get(i + 1).getRegfech();

            int numeroDatosInterpolados = RestaFecha(fechaInicio, fechaFin);

            Hidregistro hidregistro1 = new Hidregistro(0,getSerieEntrada().get(i).getHidtipomedicion(), getSerieEntrada().get(i).getHidtiporegistro(),
                    getSerieEntrada().get(i).getHidpuntomonitoreo(), getSerieEntrada().get(i).getRegfech(), getSerieEntrada().get(i).getRegval(),
                    new Date(), 2);

            hidregistros.add(hidregistro1);
            if(numeroDatosInterpolados < 5)
            {
                List<Hidregistro> hidregistrosRegresion = RealizarRegresionLineal(hidregistro1, numeroDatosInterpolados - 1);

                for (int j = 0; j < hidregistrosRegresion.size(); j++)
                {
                    hidregistros.add(hidregistrosRegresion.get(j));
                }
            }
        }

        Hidregistro hidregistro = getSerieEntrada().get(getSerieEntrada().size() - 1);
        Hidregistro hidregistro1 = new Hidregistro(0,hidregistro.getHidtipomedicion(), hidregistro.getHidtiporegistro(), hidregistro.getHidpuntomonitoreo(),
                hidregistro.getRegfech(), hidregistro.getRegval(),new Date(), 2);
        hidregistros.add(hidregistro1);

        setSerieSalida(hidregistros);
    }

    public List<Hidregistro> ObtenerSerieOriginalCompleta()
    {
        Hidregistro hidregistro = getSerieEntrada().get(0);
        Hidtiporegistro hidtiporegistro = Hidtiporegistro.findById(2);

        /*System.out.println("obtserorig: " + hidregistro.getHidpuntomonitoreo().getPunmonid() + " " +
                                            hidregistro.getHidtipomedicion().getTipmedid() + " " + "1 3");*/

        List<Hidregistro> hidregistros = Hidregistro.find("byHidpuntomonitoreoAndHidtipomedicionAndHidtiporegistroAndRegestval",
                                                        hidregistro.getHidpuntomonitoreo(),
                                                        hidregistro.getHidtipomedicion(),
                                                        hidtiporegistro,
                                                        3).fetch();
        return hidregistros;
    }

    public List<Hidregistro> ObtenerMejorSerieParaCorrelacionar()
    {
        double coeficienteCorrelacion = -1;

        Hidregistro hidregistro = getSerieEntrada().get(0);
        Hidtiporegistro hidtiporegistro = Hidtiporegistro.findById(2);
        int idPuntoMonitoreo = hidregistro.getHidpuntomonitoreo().getPunmonid();

        List<Hidregistro> mejoresRegistros = new ArrayList<Hidregistro>();
        //List<Hidpuntomonitoreo> hidpuntomonitoreos = Hidpuntomonitoreo.find("punmonid <> ?",idPuntoMonitoreo).fetch();

        List<Hidtipopuntomonitoreo> hidtipopuntomonitoreos = Hidtipopuntomonitoreo.findAll();

        System.out.println("3.1");
        //recorremos todos los puntos de monitoreo
        for (int i = 0; i < hidtipopuntomonitoreos.size(); i++)
        {
            System.out.println("3.1." + i);
            //buscamos los tipos de mediciones que posee cada punto de monitoreo
            for (int j = 0; j < hidtipopuntomonitoreos.get(i).getHidtipomedicions().size(); j++)
            {
                System.out.println("3.1." + i + "." + j);
                //comparamos si el tipo de medicion que poseen los registros es igual a algun tipo de los que posee el punto de monitoreo
                if(hidtipopuntomonitoreos.get(i).getHidtipomedicions().get(j).getTipmedid() == hidregistro.getHidtipomedicion().getTipmedid())
                {
                    //puntos de monitoreo que poseen el tipo de registros
                    List<Hidpuntomonitoreo> hidpuntomonitoreos = Hidpuntomonitoreo.find("punmonid <> ? and tippunmonid = ?",idPuntoMonitoreo, hidtipopuntomonitoreos.get(i).getTippunmonid() ).fetch();

                    System.out.println("3.1." + i + "." + j + ".T");
                    for (int k = 0; k < hidpuntomonitoreos.size(); k++)
                    {
                        System.out.println("3.1." + i + "." + j + ".T." + k);
                        List<Hidregistro> hidregistros = Hidregistro.find("punmonid = ? and regestval = ? and tipmedid = ?",
                            hidpuntomonitoreos.get(k).getPunmonid(), 3, hidregistro.getHidtipomedicion().getTipmedid()).fetch();
                        /*System.out.println("PM: " + hidpuntomonitoreos.get(k).getPunmonid() +
                                           " regest: 3" +
                                           " tipMED: " + hidregistro.getHidtipomedicion().getTipmedid());*/

                        if(hidregistros.size() > 0)
                        {
                            double coeficienteTemporal = CoeficientePearson(getSerieEntrada(), hidregistros);

                            System.out.println("coefpear: " + coeficienteTemporal);

                            if(coeficienteTemporal > coeficienteCorrelacion)
                            {
                                mejoresRegistros = hidregistros;
                                coeficienteCorrelacion = coeficienteTemporal;
                            }
                        }
                    }
                    break;
                }
            }
        }

        return mejoresRegistros;
    }

    public List<Hidregistro> RealizarRegresionLineal(Hidregistro hidregistroInicio, int numeroDatosInterpolados)
    {
        List<Hidregistro> hidregistros = new ArrayList<Hidregistro>();
        Date fechaTemporal = (Date)hidregistroInicio.getRegfech().clone();

        for (int i = 0; i < numeroDatosInterpolados; i++)
        {
            double Y = getSerieEntrada().get(i).getRegval() * regresionLineal.getPendiente() +regresionLineal.getConstante();

            fechaTemporal = ObtenerFechaMasIntervalo(fechaTemporal);

            Hidregistro hidregistro = new Hidregistro(0,hidregistroInicio.getHidtipomedicion(), hidregistroInicio.getHidtiporegistro(),
                    hidregistroInicio.getHidpuntomonitoreo(), fechaTemporal, Y, new Date(),
                    hidregistroInicio.getRegtipmet());
            hidregistros.add(hidregistro);
        }
        return hidregistros;
    }

    public int getIntervaloDias() {
        return IntervaloDias;
    }

    public void setIntervaloDias(int intervaloDias) {
        IntervaloDias = intervaloDias;
    }
}
